//////////////////////////////////////////////////////////////////////////
//Copyright (c) 2011, linlin liu
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions are met:
//* Redistributions of source code must retain the above copyright
//notice, this list of conditions and the following disclaimer.
//* Redistributions in binary form must reproduce the above copyright
//notice, this list of conditions and the following disclaimer in the
//documentation and/or other materials provided with the distribution.
//* Neither the name of the <organization> nor the
//names of its contributors may be used to endorse or promote products
//derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
//DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//////////////////////////////////////////////////////////////////////////

#include "amf0/amf0_item.h"
#include "amf0/amf0.h"
#include <boost/cstdint.hpp>

void amf::amf_item::encode(char* data, amf_data_ptr val)
{
    char* ptr = data;

    amf_integer::encode<1>(ptr, val->get_type());
    ++ptr;

    val->encode(ptr);
}

amf::amf_data_ptr amf::amf_item::decode(const char* data, boost::uint32_t quota)
{
    using namespace amf;

    if (quota < 1)
    {
        return amf_data_ptr(new amf_unsupported());
    }

    const char* ptr = data;

    AMF_TYPE value_type = (AMF_TYPE) * ptr;
    ++ptr;

    boost::uint32_t left_quota = quota - 1;

    amf_data_ptr val(new amf_undefined());

    if (value_type == AMF_TYPE_NUMERIC)
    {
        val = amf_data_ptr(new amf_numeric);
    }
    else if (value_type == AMF_TYPE_BOOLEAN)
    {
        val = amf_data_ptr(new amf_boolean);
    }
    else if (value_type == AMF_TYPE_STRING)
    {
        val = amf_data_ptr(new amf_string);
    }
    else if (value_type == AMF_TYPE_OBJECT)
    {
        val = amf_data_ptr(new amf_object);
    }
    else if (value_type == AMF_TYPE_NULL_VALUE)
    {
        val = amf_data_ptr(new amf_null);
    }
    else if (value_type == AMF_TYPE_UNDEFINED)
    {
        val = amf_data_ptr(new amf_undefined);
    }
    else if (value_type == AMF_TYPE_REFERENCE)
    {
        val = amf_data_ptr(new amf_reference);
    }
    else if (value_type == AMF_TYPE_ECMA_ARRAY)
    {
        val = amf_data_ptr(new amf_ecma_array);
    }
    else if (value_type == AMF_TYPE_STRICT_ARRAY)
    {
        val = amf_data_ptr(new amf_strict_array);
    }
    else if (value_type == AMF_TYPE_DATE)
    {
        val = amf_data_ptr(new amf_date);
    }
    else if (value_type == AMF_TYPE_LONG_STRING)
    {
        val = amf_data_ptr(new amf_long_string);
    }
    else if (value_type == AMF_TYPE_OBJECT_END)
    {
        val = amf_data_ptr(new amf_undefined);
    }
    else if (value_type == AMF_TYPE_UNSUPPORTED)
    {
        val = amf_data_ptr(new amf_unsupported);
    }

    if (val->decode(ptr, left_quota) == AMF_DECODE_FAILED)
    {
        return amf_data_ptr(new amf_unsupported());
    }
    else
    {
        return val;
    }
}